<template>
  <section
    :style="{ ...styles.box, ...boxStyle }"
    class="v-screen-box"
    ref="box"
  >
    <div
      :style="{ ...styles.wrapper, ...wrapperStyle }"
      class="screen-wrapper"
      ref="screenWrapper"
    >
      <slot></slot>
    </div>
  </section>
</template>

<script>
export default {
  name: "Scale-screen",
  props: {
    width: {
      type: [String, Number],
      default: 1920,
    },
    height: {
      type: [String, Number],
      default: 1080,
    },
    fullScreen: {
      type: Boolean,
      default: false,
    },
    autoScale: {
      type: [Object, Boolean],
      default: true,
    },
    delay: {
      type: Number,
      default: 500,
    },
    boxStyle: {
      type: Object,
      default: () => ({}),
    },
    wrapperStyle: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      state: {
        width: 0,
        height: 0,
        originalWidth: 0,
        originalHeight: 0,
        observer: null,
      },
      styles: {
        box: {
          overflow: "hidden",
          backgroundSize: `100% 100%`,
          background: `#000`,
          width: `100vw`,
          height: `100vh`,
        },
        wrapper: {
          transitionProperty: `all`,
          transitionTimingFunction: `cubic-bezier(0.4, 0, 0.2, 1)`,
          transitionDuration: `500ms`,
          position: `relative`,
          overflow: `hidden`,
          zIndex: 100,
          transformOrigin: `left top`,
        },
      },
    };
  },
  mounted() {
    this.$nextTick(async () => {
      await this.initSize();
      this.updateSize();
      // 暂时移除 updateScale()
      this.updateScale();
      this.addListener();
    });
  },
  beforeDestroy() {
    this.clearListener();
  },
  methods: {
    debounce(fn, delay) {
      let timer = null;
      return function (...args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          fn.apply(null, args);
          clearTimeout(timer);
        }, delay > 0 ? delay : 100);
      };
    },
    async initSize() {
      this.$refs.box.scrollLeft = 0;
      this.$refs.box.scrollTop = 0;
      return new Promise((resolve) => {
        this.$nextTick(() => {
          if (this.width && this.height) {
            this.state.width = this.width;
            this.state.height = this.height;
          } else {
            this.state.width = this.$refs.screenWrapper.clientWidth;
            this.state.height = this.$refs.screenWrapper.clientHeight;
          }
          if (!this.state.originalWidth || !this.state.originalHeight) {
            this.state.originalWidth = window.screen.width;
            this.state.originalHeight = window.screen.height;
          }
          resolve();
        });
      });
    },
    updateSize() {
      if (this.state.width && this.state.height) {
        this.$refs.screenWrapper.style.width = `${this.state.width}px`;
        this.$refs.screenWrapper.style.height = `${this.state.height}px`;
      } else {
        this.$refs.screenWrapper.style.width = `${this.state.originalWidth}px`;
        this.$refs.screenWrapper.style.height = `${this.state.originalHeight}px`;
      }
    },
    updateScale() {
      const currentWidth = document.body.clientWidth;
      const currentHeight = document.body.clientHeight;
      const realWidth = this.state.width || this.state.originalWidth;
      const realHeight = this.state.height || this.state.originalHeight;
      const widthScale = currentWidth / realWidth;
      const heightScale = currentHeight / realHeight;
      if (this.fullScreen) {
        this.$refs.screenWrapper.style.transform = `scale(${widthScale},${heightScale})`;
        return;
      }
      const scale = Math.min(widthScale, heightScale);
      this.autoScaleWrapper(scale);
    },
    autoScaleWrapper(scale) {
      const domWidth = this.$refs.screenWrapper.clientWidth;
      const domHeight = this.$refs.screenWrapper.clientHeight;
      const currentWidth = document.body.clientWidth;
      const currentHeight = document.body.clientHeight;
      this.$refs.screenWrapper.style.transform = `scale(${scale},${scale})`;
      let mx = Math.max((currentWidth - domWidth * scale) / 2, 0);
      let my = Math.max((currentHeight - domHeight * scale) / 2, 0);
      if (typeof this.autoScale === "object") {
        if (!this.autoScale.x) mx = 0;
        if (!this.autoScale.y) my = 0;
      }
      this.$refs.screenWrapper.style.margin = `${my}px ${mx}px`;
    },
    addListener() {
      window.addEventListener("resize", this.debounce(this.onResize, this.delay));
    },
    clearListener() {
      window.removeEventListener("resize", this.debounce(this.onResize, this.delay));
    },
    async onResize() {
      await this.initSize();
      this.updateSize();
      this.updateScale();
    },
  },
};
</script>


<style scoped>
.v-screen-box {
  width: 100vw;
  height: 100vh;
}
.screen-wrapper {
  transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
  z-index: 100;
}
</style>
